{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "b47c2277",
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "from agents import Agent, WebSearchTool, trace, Runner, gen_trace_id, function_tool\n",
    "from agents.model_settings import ModelSettings\n",
    "from pydantic import BaseModel, Field\n",
    "import asyncio\n",
    "import sendgrid\n",
    "import os\n",
    "from sendgrid.helpers.mail import Mail, Email, To, From, content\n",
    "from typing import Dict\n",
    "from IPython.display  import display, Markdown"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "7e54bca7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "load_dotenv (override=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a146ed58",
   "metadata": {},
   "source": [
    "## OpenAI Hosted Tools\n",
    "\n",
    "OpenAI Agents SDK includes the following hosted tools:\n",
    "\n",
    "The `WebSearchTool` lets an agent search the web.  \n",
    "The `FileSearchTool` allows retrieving information from your OpenAI Vector Stores.  \n",
    "The `ComputerTool` allows automating computer use tasks like taking screenshots and clicking.\n",
    "\n",
    "\n",
    "Costs are here: https://platform.openai.com/docs/pricing#web-search"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4f8fabe7",
   "metadata": {},
   "outputs": [],
   "source": [
    "INSTRUCTIONS = \"You are a research assistant. Given a search term, you search the web for that term and \\\n",
    "produce a concise summary of the results. The summary must be 2-3 paragraphs and less than 300 \\\n",
    "words. Capture the main points. Write succintly, no need to have complete sentences or good \\\n",
    "grammar. This will be consumed by someone synthesizing a report, so it's vital you capture the \\\n",
    "essence and ignore any fluff. Do not include any additional commentary other than the summary itself\"\n",
    "\n",
    "search_agent = Agent(\n",
    "    name = \"search agent\",\n",
    "    instructions=INSTRUCTIONS,\n",
    "    model='gpt-4o-mini',\n",
    "    tools = [WebSearchTool(search_context_size=\"low\")],\n",
    "    model_settings=ModelSettings(tool_choice=\"required\")\n",
    "\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "632aff92",
   "metadata": {},
   "outputs": [],
   "source": [
    "OPEN_AI_KEY = os.getenv(\"OPENAI_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "982817b3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Open AI key is found and starts with sk-proj-\n"
     ]
    }
   ],
   "source": [
    "if OPEN_AI_KEY:\n",
    "    print(f\"Open AI key is found and starts with {OPEN_AI_KEY[:8]}\")\n",
    "else:\n",
    "    print(f\"Open AI key is not found. Check env and docs\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e0bbe7c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "In 2025, several AI agent frameworks have emerged, enhancing the development and deployment of intelligent agents across various applications. Dalet introduced \"Dalia,\" an agentic AI solution integrated throughout its media ecosystem, offering a unified, natural-language interface for tasks like asset management and live ingests. ([tvtechnology.com](https://www.tvtechnology.com/news/dalet-introduces-dalia-agentic-ai-across-entire-ecosystem?utm_source=openai)) Cisco unveiled \"Connected Intelligence,\" a suite of AI agents within its Webex platform, including task agents, notetakers, and meeting schedulers, aiming to boost productivity in collaboration workflows. ([techradar.com](https://www.techradar.com/pro/cisco-goes-all-in-on-agents-and-it-could-mean-big-changes-in-your-workplace?utm_source=openai)) OutSystems launched \"Agent Workbench,\" a low-code platform enabling enterprises to implement agentic AI for streamlining operations and modernizing legacy systems. ([techradar.com](https://www.techradar.com/pro/outsystems-agent-workbench-reaches-general-availability-helping-enterprises-streamline-operations-through-agentic-ai?utm_source=openai))\n",
       "\n",
       "Academically, frameworks like \"Agent Lightning\" and \"Cognitive Kernel-Pro\" have been developed. Agent Lightning is a flexible framework that decouples agent execution from training, facilitating reinforcement learning-based training of large language models for any AI agent. ([arxiv.org](https://arxiv.org/abs/2508.03680?utm_source=openai)) Cognitive Kernel-Pro is an open-source, multi-module agent framework designed to democratize the development and evaluation of advanced AI agents, achieving state-of-the-art results among open-source agents. ([arxiv.org](https://arxiv.org/abs/2508.00414?utm_source=openai)) Additionally, the Model Context Protocol (MCP), introduced by Anthropic in November 2024, has been adopted by major AI providers, including OpenAI and Google DeepMind, to standardize AI system integration and data sharing. ([en.wikipedia.org](https://en.wikipedia.org/wiki/Model_Context_Protocol?utm_source=openai)) "
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "message = \"Latest AI Agent frameworks in 2025\"\n",
    "\n",
    "with trace(\"Latest Agentic AI framweork\"):\n",
    "    result = await Runner.run(search_agent, message)\n",
    "    \n",
    "    \n",
    "display(Markdown(result.final_output))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e588412a",
   "metadata": {},
   "source": [
    "#### PLANNER AGENTS"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20553de8",
   "metadata": {},
   "source": [
    "Planner Agents - It will receive a query and come up with a handful of searches that it should run. Limiting the search to three for this purpose/project due to costing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "b364fafd",
   "metadata": {},
   "outputs": [],
   "source": [
    "Number_of_Searches = 3\n",
    "#This is the number of searches it should run\n",
    "\n",
    "INSTRUCTIONS = f\"You are a helpful research assistant. Given a query , come up with a set of web services \\\n",
    "    to perform to best answer the query. Output {Number_of_Searches} terms to query for.\"\n",
    "\n",
    "class WebSearchItem(BaseModel):\n",
    "    reason:str\n",
    "    \"Your reasoning for why this search is important to the query\"\n",
    "\n",
    "\n",
    "    query:str\n",
    "    \"The search term to use for the web search\"\n",
    "\n",
    "\n",
    "class WebSearchPlan(BaseModel):\n",
    "\n",
    "    searches: list[WebSearchItem]\n",
    "    \"\"\"A list of web searches to perform to best answer the query.\"\"\"\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "planner_agent = Agent(\n",
    "    name = \"PlannerAgent\",\n",
    "    instructions = INSTRUCTIONS,\n",
    "    model=\"gpt-4o-mini\",\n",
    "    output_type=WebSearchPlan\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "7b3b31c8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "searches=[WebSearchItem(reason='To gather information about the most recent developments and frameworks in agentic AI expected in 2025.', query='latest agentic AI frameworks 2025'), WebSearchItem(reason='To explore predictions and trends in technology specifically regarding agentic AI in 2025.', query='agentic AI trends 2025'), WebSearchItem(reason='To find scholarly articles, white papers, or technical reports on agentic AI frameworks that will be relevant in 2025.', query='agentic AI research papers 2025')]\n"
     ]
    }
   ],
   "source": [
    "message = \"Latest Agentic AI Frameworks in 2025\"\n",
    "\n",
    "with trace(\"Search\"):\n",
    "    result = await Runner.run(planner_agent,message)\n",
    "\n",
    "    print(result.final_output)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "1296a060",
   "metadata": {},
   "outputs": [],
   "source": [
    "@function_tool\n",
    "def send_email(subject: str, html_body: str) -> Dict[str, str]:\n",
    "    \"\"\" Send out an email with the given subject and HTML body \"\"\"\n",
    "    sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))\n",
    "    from_email = Email(\"toyeladun@gmail.com\") # Change this to your verified email\n",
    "    to_email = To(\"toyeladunr@gmail.com\") # Change this to your email\n",
    "    content = Content(\"text/html\", html_body)\n",
    "    mail = Mail(from_email, to_email, subject, content).get()\n",
    "    response = sg.client.mail.send.post(request_body=mail)\n",
    "    return {\"status\": \"success\"}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "5ba4dd04",
   "metadata": {},
   "outputs": [],
   "source": [
    "INSTRUCTIONS = \"\"\"You are able to send a nicely formatted HTML email based on a detailed report.\n",
    "You will be provided with a detailed report. You should use your tool to send one email, providing the \n",
    "report converted into clean, well presented HTML with an appropriate subject line.\"\"\"\n",
    "\n",
    "email_agent = Agent(\n",
    "    name=\"Email agent\",\n",
    "    instructions=INSTRUCTIONS,\n",
    "    tools=[send_email],\n",
    "    model=\"gpt-4o-mini\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "6efe367f",
   "metadata": {},
   "outputs": [],
   "source": [
    "INSTRUCTIONS = (\n",
    "    \"You are a senior researcher tasked with writing a cohesive report for a research query. \"\n",
    "    \"You will be provided with the original query, and some initial research done by a research assistant.\\n\"\n",
    "    \"You should first come up with an outline for the report that describes the structure and \"\n",
    "    \"flow of the report. Then, generate the report and return that as your final output.\\n\"\n",
    "    \"The final output should be in markdown format, and it should be lengthy and detailed. Aim \"\n",
    "    \"for 5-10 pages of content, at least 1000 words.\"\n",
    ")\n",
    "\n",
    "\n",
    "class ReportData(BaseModel):\n",
    "    short_summary: str = Field(description=\"A short 2-3 sentence summary of the findings.\")\n",
    "\n",
    "    markdown_report: str = Field(description=\"The final report\")\n",
    "\n",
    "    follow_up_questions: list[str] = Field(description=\"Suggested topics to research further\")\n",
    "\n",
    "\n",
    "writer_agent = Agent(\n",
    "    name=\"WriterAgent\",\n",
    "    instructions=INSTRUCTIONS,\n",
    "    model=\"gpt-4o-mini\",\n",
    "    output_type=ReportData,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "07df3eb0",
   "metadata": {},
   "outputs": [],
   "source": [
    "async def plan_searches(query: str):\n",
    "    \"\"\" Use the planner_agent to plan which searches to run for the query \"\"\"\n",
    "    print(\"Planning searches...\")\n",
    "    result = await Runner.run(planner_agent, f\"Query: {query}\")\n",
    "    print(f\"Will perform {len(result.final_output.searches)} searches\")\n",
    "    return result.final_output\n",
    "\n",
    "async def perform_searches(search_plan: WebSearchPlan):\n",
    "    \"\"\" Call search() for each item in the search plan \"\"\"\n",
    "    print(\"Searching...\")\n",
    "    tasks = [asyncio.create_task(search(item)) for item in search_plan.searches]\n",
    "    results = await asyncio.gather(*tasks)\n",
    "    print(\"Finished searching\")\n",
    "    return results\n",
    "\n",
    "async def search(item: WebSearchItem):\n",
    "    \"\"\" Use the search agent to run a web search for each item in the search plan \"\"\"\n",
    "    input = f\"Search term: {item.query}\\nReason for searching: {item.reason}\"\n",
    "    result = await Runner.run(search_agent, input)\n",
    "    return result.final_output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "472724de",
   "metadata": {},
   "outputs": [],
   "source": [
    "async def write_report(query: str, search_results: list[str]):\n",
    "    \"\"\" Use the writer agent to write a report based on the search results\"\"\"\n",
    "    print(\"Thinking about report...\")\n",
    "    input = f\"Original query: {query}\\nSummarized search results: {search_results}\"\n",
    "    result = await Runner.run(writer_agent, input)\n",
    "    print(\"Finished writing report\")\n",
    "    return result.final_output\n",
    "\n",
    "async def send_email(report: ReportData):\n",
    "    \"\"\" Use the email agent to send an email with the report \"\"\"\n",
    "    print(\"Writing email...\")\n",
    "    result = await Runner.run(email_agent, report.markdown_report)\n",
    "    print(\"Email sent\")\n",
    "    return report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "904a90d8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting research...\n",
      "Planning searches...\n",
      "Will perform 1 searches\n",
      "Searching...\n",
      "Finished searching\n",
      "Thinking about report...\n",
      "Finished writing report\n",
      "Writing email...\n"
     ]
    }
   ],
   "source": [
    "query =\"Latest AI Agent frameworks in 2025\"\n",
    "\n",
    "with trace(\"Research trace\"):\n",
    "    print(\"Starting research...\")\n",
    "    search_plan = await plan_searches(query)\n",
    "    search_results = await perform_searches(search_plan)\n",
    "    report = await write_report(query, search_results)\n",
    "    await send_email(report)  \n",
    "    print(\"Hooray!\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
